home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue60 / Alfresco / AABinTre.pas next >
Encoding:
Pascal/Delphi Source File  |  2000-06-25  |  38.2 KB  |  1,221 lines

  1. {*********************************************************}
  2. {* AABinTre                                              *}
  3. {* Copyright (c) Julian M Bucknall 1998-1999             *}
  4. {* All rights reserved.                                  *}
  5. {*********************************************************}
  6. {* Algorithms Alfresco binary tree unit                  *}
  7. {*********************************************************}
  8.  
  9. {Note: this unit is released as freeware. In other words, you are free
  10.        to use this unit in your own applications, however I retain all
  11.        copyright to the code. JMB}
  12.  
  13. unit AABinTre;
  14.  
  15. {Version 1: initial release}
  16. {Version 2: New insert-or-get in binary search & red-black tree}
  17.  
  18. interface
  19.  
  20. uses
  21.   SysUtils;
  22.  
  23. {$IFOPT D+}
  24. {$DEFINE InDebugMode}
  25. {$ENDIF}
  26.  
  27. {$DEFINE UseNodeManager}
  28.  
  29. const
  30.   PageNodeCount = 30;
  31.  
  32. type
  33.   TaaCompareFunction = function (aItem1, aItem2 : pointer) : integer;
  34.  
  35. const
  36.   aaLeft  = true;
  37.   aaRight = false;
  38.   aaRed   = true;
  39.   aaBlack = false;
  40.  
  41. type
  42.   TaaBinaryTree = class;     {forward declaration}
  43.  
  44.   TaaTraversalMode = (       {different traversal modes..}
  45.          tmPreOrder,         {..pre-order}
  46.          tmInOrder,          {..in-order}
  47.          tmPostOrder,        {..post-order}
  48.          tmLevelOrder);      {..level-order}
  49.  
  50.   PaaBTNode = ^TaaBTNode;    {binary tree node}
  51.   TaaBTNode = packed record
  52.     btParent : PaaBTNode;
  53.     btChild  : array [boolean] of PaaBTNode;
  54.     btData   : pointer;
  55.     case boolean of
  56.       false : (btExtra  : longint);
  57.       true  : (btColor  : boolean);
  58.   end;
  59.  
  60.   TaaDisposeItem = procedure (aItem : pointer);
  61.     {-procedure prototype to dispose of an item}
  62.  
  63.   TaaProcessNode = function (aNode      : PaaBTNode;
  64.                              aExtraData : pointer) : boolean;
  65.     {-function prototype to process a node}
  66.  
  67.   TaaBinaryTree = class           {binary tree class}
  68.     private
  69.       FCount   : integer;
  70.       FDispose : TaaDisposeItem;
  71.       FHead    : PaaBTNode;
  72.     protected
  73.       function btLevelOrder(aAction : TaaProcessNode;
  74.                             aExtraData : pointer) : PaaBTNode;
  75.       function btNoRecInOrder(aAction : TaaProcessNode;
  76.                               aExtraData : pointer) : PaaBTNode;
  77.       function btNoRecPostOrder(aAction : TaaProcessNode;
  78.                                 aExtraData : pointer) : PaaBTNode;
  79.       function btNoRecPreOrder(aAction : TaaProcessNode;
  80.                                aExtraData : pointer) : PaaBTNode;
  81.       function btRecInOrder(aNode   : PaaBTNode;
  82.                             aAction : TaaProcessNode;
  83.                             aExtraData : pointer) : PaaBTNode;
  84.       function btRecPostOrder(aNode   : PaaBTNode;
  85.                               aAction : TaaProcessNode;
  86.                               aExtraData : pointer) : PaaBTNode;
  87.       function btRecPreOrder(aNode   : PaaBTNode;
  88.                              aAction : TaaProcessNode;
  89.                              aExtraData : pointer) : PaaBTNode;
  90.     public
  91.       constructor Create(aDisposeItem : TaaDisposeItem);
  92.       destructor Destroy; override;
  93.  
  94.       procedure Clear;
  95.       procedure Delete(aNode : PaaBTNode);
  96.       function InsertAt(aParentNode  : PaaBTNode;
  97.                         aAsLeftChild : boolean;
  98.                         aItem        : pointer) : PaaBTNode;
  99.       function Root : PaaBTNode;
  100.       function Traverse(aMode         : TaaTraversalMode;
  101.                         aAction       : TaaProcessNode;
  102.                         aExtraData    : pointer;
  103.                         aUseRecursion : boolean) : PaaBTNode;
  104.  
  105.       property Count : integer read FCount;
  106.   end;
  107.  
  108.   TaaBinarySearchTree = class     {binary search tree class}
  109.     private
  110.       FBinTree : TaaBinaryTree;
  111.       FCompare : TaaCompareFunction;
  112.       FCount   : integer;
  113.     protected
  114.       function bstFindItem(aItem    : pointer;
  115.                        var aNode    : PaaBTNode;
  116.                        var aUseLeft : boolean) : boolean;
  117.       function bstFindNodeToDelete(aItem : pointer) : PaaBTNode;
  118.       function bstInsertPrim(aItem    : pointer;
  119.                          var aExists  : boolean;
  120.                          var aUseLeft : boolean) : PaaBTNode;
  121.     public
  122.       constructor Create(aCompare : TaaCompareFunction;
  123.                          aDispose : TaaDisposeItem);
  124.       destructor Destroy; override;
  125.  
  126.       procedure Clear;
  127.       procedure Delete(aItem : pointer); virtual;
  128.       function Find(aKeyItem : pointer) : pointer;
  129.       procedure Insert(aItem : pointer); virtual;
  130.       function InsertOrGet(aItem : pointer; var aCurItem : pointer)
  131.                                                   : boolean; virtual;
  132.       function Traverse(aMode         : TaaTraversalMode;
  133.                         aAction       : TaaProcessNode;
  134.                         aExtraData    : pointer;
  135.                         aUseRecursion : boolean) : pointer;
  136.  
  137.       property Count : integer read FCount;
  138.       property BinaryTree : TaaBinaryTree read FBinTree;
  139.   end;
  140.  
  141.   TaaRedBlackTree = class(TaaBinarySearchTree)  {red-black tree class}
  142.     private
  143.     protected
  144.       procedure rbtBalanceAfterInsert(aNode  : PaaBTNode);
  145.       function rbtPromote(aNode  : PaaBTNode) : PaaBTNode;
  146.     public
  147.       procedure Delete(aItem : pointer); override;
  148.       procedure Insert(aItem : pointer); override;
  149.       function InsertOrGet(aItem : pointer; var aCurItem : pointer)
  150.                                                   : boolean; override;
  151.   end;
  152.  
  153. type
  154.   TaaDrawBinaryNode = procedure (aNode  : PaaBTNode;
  155.                                  aStrip : integer;
  156.                                  aColumn: integer;
  157.                                  aParentStrip : integer;
  158.                                  aParentColumn: integer;
  159.                                  aExtraData   : pointer);
  160.  
  161. procedure DrawBinaryTree(aTree      : TObject;
  162.                          aDrawNode  : TaaDrawBinaryNode;
  163.                          aExtraData : pointer);
  164.  
  165. implementation
  166.  
  167. uses
  168.   AALnkLst;
  169.  
  170. {===NodeManager for binary tree nodes================================}
  171. type
  172.   PnmPage = ^TnmPage;
  173.   TnmPage = packed record
  174.     nmpNext  : PnmPage;
  175.     nmpNodes : array [0..pred(PageNodeCount)] of TaaBTNode;
  176.   end;
  177. {--------}
  178. var
  179.   nmFreeList : PaaBTNode;
  180.   nmPageList : PnmPage;
  181. {--------}
  182. procedure nmFreeNode(aNode : PaaBTNode);
  183. begin
  184.   {$IFDEF UseNodeManager}
  185.   {add the node to the top of the free list}
  186.   aNode^.btParent := nmFreeList;
  187.   nmFreeList := aNode;
  188.   {$ELSE}
  189.   Dispose(aNode);
  190.   {$ENDIF}
  191. end;
  192. {--------}
  193. procedure nmAllocPage;
  194. var
  195.   NewPage : PnmPage;
  196.   i       : integer;
  197. begin
  198.   {get a new page}
  199.   New(NewPage);
  200.   {add it to the current list of pages}
  201.   NewPage^.nmpNext := nmPageList;
  202.   nmPageList := NewPage;
  203.   {add all the nodes on the page to the free list}
  204.   for i := 0 to pred(PageNodeCount) do
  205.     nmFreeNode(@NewPage^.nmpNodes[i]);
  206. end;
  207. {--------}
  208. function nmAllocNode : PaaBTNode;
  209. begin
  210.   {$IFDEF UseNodeManager}
  211.   {if the free list is empty, allocate a new page of nodes}
  212.   if (nmFreeList = nil) then
  213.     nmAllocPage;
  214.   {return the first node on the free list}
  215.   Result := nmFreeList;
  216.   nmFreeList := Result^.btParent;
  217.   {$ELSE}
  218.   New(Result);
  219.   {$ENDIF}
  220.   {$IFDEF InDebugMode}
  221.   Result^.btParent := nil;
  222.   Result^.btChild[aaLeft] := nil;
  223.   Result^.btChild[aaRight] := nil;
  224.   Result^.btData := nil;
  225.   Result^.btExtra := 0;
  226.   {$ENDIF}
  227. end;
  228. {====================================================================}
  229.  
  230.  
  231. {===Helper routines==================================================}
  232. function DisposeNode(aNode      : PaaBTNode;
  233.                      aExtraData : pointer) : boolean; far;
  234. var
  235.   DisposeItem : TaaDisposeItem absolute aExtraData;
  236. begin
  237.   if (aExtraData <> nil) then
  238.     DisposeItem(aNode^.btData);
  239.   nmFreeNode(aNode);
  240.   Result := true;
  241. end;
  242. {====================================================================}
  243.  
  244.  
  245. {===TaaBinaryTree====================================================}
  246. constructor TaaBinaryTree.Create(aDisposeItem : TaaDisposeItem);
  247. begin
  248.   inherited Create;
  249.   FDispose := aDisposeItem;
  250.   {allocate a head node, eventually the root node of the tree will be
  251.    its left child}
  252.   FHead := nmAllocNode;
  253.   FHead^.btParent := nil;
  254.   FHead^.btChild[aaLeft] := nil;
  255.   FHead^.btChild[aaRight] := nil;
  256.   FHead^.btData := nil;
  257.   FHead^.btExtra := 0;
  258. end;
  259. {--------}
  260. destructor TaaBinaryTree.Destroy;
  261. begin
  262.   Clear;
  263.   nmFreeNode(FHead);
  264.   inherited Destroy;
  265. end;
  266. {--------}
  267. function TaaBinaryTree.btLevelOrder(aAction : TaaProcessNode;
  268.                                     aExtraData : pointer) : PaaBTNode;
  269. var
  270.   Queue : TaaQueue;
  271.   Node  : PaaBTNode;
  272. begin
  273.   {assume we won't get a node selected}
  274.   Result := nil;
  275.   {simple case first}
  276.   if (FCount = 0) then
  277.     Exit;
  278.   {create the queue}
  279.   Queue := TaaQueue.Create;
  280.   try
  281.     {enqueue the root}
  282.     Queue.Enqueue(FHead^.btChild[aaLeft]);
  283.     {continue until the queue is empty}
  284.     while not Queue.IsEmpty do begin
  285.       {get the node at the head of the queue}
  286.       Node := Queue.Dequeue;
  287.       {perform the action on it, if this returns false (ie, don't
  288.        continue), return this node}
  289.       if not aAction(Node, aExtraData) then begin
  290.         Result := Node;
  291.         Queue.Clear;
  292.       end
  293.       {otherwise, continue}
  294.       else begin
  295.         {enqueue the left child, if it's not nil}
  296.         if (Node^.btChild[aaLeft] <> nil) then
  297.           Queue.Enqueue(Node^.btChild[aaLeft]);
  298.         {enqueue the right child, if it's not nil}
  299.         if (Node^.btChild[aaRight] <> nil) then
  300.           Queue.Enqueue(Node^.btChild[aaRight]);
  301.       end;
  302.     end;
  303.   finally
  304.     {destroy the queue}
  305.     Queue.Free;
  306.   end;
  307. end;
  308. {--------}
  309. function TaaBinaryTree.btNoRecInOrder(aAction : TaaProcessNode;
  310.                                       aExtraData : pointer) : PaaBTNode;
  311. var
  312.   Stack : TaaStack;
  313.   Node  : PaaBTNode;
  314. begin
  315.   {assume we won't get a node selected}
  316.   Result := nil;
  317.   {simple case first}
  318.   if (FCount = 0) then
  319.     Exit;
  320.   {create the stack}
  321.   Stack := TaaStack.Create;
  322.   try
  323.     {push the root}
  324.     Stack.Push(FHead^.btChild[aaLeft]);
  325.     {continue until the stack is empty}
  326.     while not Stack.IsEmpty do begin
  327.       {get the node at the head of the queue}
  328.       Node := Stack.Pop;
  329.       {if it's nil, pop the next node, perform the action on it, if
  330.        this returns false (ie, don't continue), return this node}
  331.       if (Node = nil) then begin
  332.         Node := Stack.Pop;
  333.         if not aAction(Node, aExtraData) then begin
  334.           Result := Node;
  335.           Stack.Clear;
  336.         end;
  337.       end
  338.       {otherwise, the children of the node have not been pushed yet}
  339.       else begin
  340.         {push the right child, if it's not nil}
  341.         if (Node^.btChild[aaRight] <> nil) then
  342.           Stack.Push(Node^.btChild[aaRight]);
  343.         {push the node, followed by a nil pointer}
  344.         Stack.Push(Node);
  345.         Stack.Push(nil);
  346.         {push the left child, if it's not nil}
  347.         if (Node^.btChild[aaLeft] <> nil) then
  348.           Stack.Push(Node^.btChild[aaLeft]);
  349.       end;
  350.     end;
  351.   finally
  352.     {destroy the stack}
  353.     Stack.Free;
  354.   end;
  355. end;
  356. {--------}
  357. function TaaBinaryTree.btNoRecPostOrder(aAction : TaaProcessNode;
  358.                                         aExtraData : pointer) : PaaBTNode;
  359. var
  360.   Stack : TaaStack;
  361.   Node  : PaaBTNode;
  362. begin
  363.   {assume we won't get a node selected}
  364.   Result := nil;
  365.   {simple case first}
  366.   if (FCount = 0) then
  367.     Exit;
  368.   {create the stack}
  369.   Stack := TaaStack.Create;
  370.   try
  371.     {push the root}
  372.     Stack.Push(FHead^.btChild[aaLeft]);
  373.     {continue until the stack is empty}
  374.     while not Stack.IsEmpty do begin
  375.       {get the node at the head of the queue}
  376.       Node := Stack.Pop;
  377.       {if it's nil, pop the next node, perform the action on it, if
  378.        this returns false (ie, don't continue), return this node}
  379.       if (Node = nil) then begin
  380.         Node := Stack.Pop;
  381.         if not aAction(Node, aExtraData) then begin
  382.           Result := Node;
  383.           Stack.Clear;
  384.         end;
  385.       end
  386.       {otherwise, the children of the node have not been pushed yet}
  387.       else begin
  388.         {push the node, followed by a nil pointer}
  389.         Stack.Push(Node);
  390.         Stack.Push(nil);
  391.         {push the right child, if it's not nil}
  392.         if (Node^.btChild[aaRight] <> nil) then
  393.           Stack.Push(Node^.btChild[aaRight]);
  394.         {push the left child, if it's not nil}
  395.         if (Node^.btChild[aaLeft] <> nil) then
  396.           Stack.Push(Node^.btChild[aaLeft]);
  397.       end;
  398.     end;
  399.   finally
  400.     {destroy the stack}
  401.     Stack.Free;
  402.   end;
  403. end;
  404. {--------}
  405. function TaaBinaryTree.btNoRecPreOrder(aAction : TaaProcessNode;
  406.                                        aExtraData : pointer) : PaaBTNode;
  407. var
  408.   Stack : TaaStack;
  409.   Node  : PaaBTNode;
  410. begin
  411.   {assume we won't get a node selected}
  412.   Result := nil;
  413.   {simple case first}
  414.   if (FCount = 0) then
  415.     Exit;
  416.   {create the stack}
  417.   Stack := TaaStack.Create;
  418.   try
  419.     {push the root}
  420.     Stack.Push(FHead^.btChild[aaLeft]);
  421.     {continue until the stack is empty}
  422.     while not Stack.IsEmpty do begin
  423.       {get the node at the head of the queue}
  424.       Node := Stack.Pop;
  425.       {perform the action on it, if this returns false (ie, don't
  426.        continue), return this node}
  427.       if not aAction(Node, aExtraData) then begin
  428.         Result := Node;
  429.         Stack.Clear;
  430.       end
  431.       {otherwise, continue}
  432.       else begin
  433.         {push the right child, if it's not nil}
  434.         if (Node^.btChild[aaRight] <> nil) then
  435.           Stack.Push(Node^.btChild[aaRight]);
  436.         {push the left child, if it's not nil}
  437.         if (Node^.btChild[aaLeft] <> nil) then
  438.           Stack.Push(Node^.btChild[aaLeft]);
  439.       end;
  440.     end;
  441.   finally
  442.     {destroy the stack}
  443.     Stack.Free;
  444.   end;
  445. end;
  446. {--------}
  447. function TaaBinaryTree.btRecInOrder(aNode   : PaaBTNode;
  448.                                     aAction : TaaProcessNode;
  449.                                     aExtraData : pointer) : PaaBTNode;
  450. begin
  451.   Result := nil;
  452.   if (aNode^.btChild[aaLeft] <> nil) then begin
  453.     Result := btRecInOrder(aNode^.btChild[aaLeft], aAction, aExtraData);
  454.     if (Result <> nil) then Exit;
  455.   end;
  456.   if not aAction(aNode, aExtraData) then begin
  457.     Result := aNode;
  458.     Exit;
  459.   end;
  460.   if (aNode^.btChild[aaRight] <> nil) then begin
  461.     Result := btRecInOrder(aNode^.btChild[aaRight], aAction, aExtraData);
  462.   end;
  463. end;
  464. {--------}
  465. function TaaBinaryTree.btRecPostOrder(aNode   : PaaBTNode;
  466.                                       aAction : TaaProcessNode;
  467.                                       aExtraData : pointer) : PaaBTNode;
  468. begin
  469.   Result := nil;
  470.   if (aNode^.btChild[aaLeft] <> nil) then begin
  471.     Result := btRecPostOrder(aNode^.btChild[aaLeft], aAction, aExtraData);
  472.     if (Result <> nil) then Exit;
  473.   end;
  474.   if (aNode^.btChild[aaRight] <> nil) then begin
  475.     Result := btRecPostOrder(aNode^.btChild[aaRight], aAction, aExtraData);
  476.     if (Result <> nil) then Exit;
  477.   end;
  478.   if not aAction(aNode, aExtraData) then begin
  479.     Result := aNode;
  480.   end;
  481. end;
  482. {--------}
  483. function TaaBinaryTree.btRecPreOrder(aNode   : PaaBTNode;
  484.                                      aAction : TaaProcessNode;
  485.                                      aExtraData : pointer) : PaaBTNode;
  486. begin
  487.   Result := nil;
  488.   if not aAction(aNode, aExtraData) then begin
  489.     Result := aNode;
  490.     Exit;
  491.   end;
  492.   if (aNode^.btChild[aaLeft] <> nil) then begin
  493.     Result := btRecPreOrder(aNode^.btChild[aaLeft], aAction, aExtraData);
  494.     if (Result <> nil) then Exit;
  495.   end;
  496.   if (aNode^.btChild[aaRight] <> nil) then begin
  497.     Result := btRecPreOrder(aNode^.btChild[aaRight], aAction, aExtraData);
  498.   end;
  499. end;
  500. {--------}
  501. procedure TaaBinaryTree.Clear;
  502. begin
  503.   {to clear a binary tree, we perform a postorder traversal, with the
  504.    action on each node being its disposal}
  505.   btNoRecPostOrder(DisposeNode, @FDispose);
  506.   FCount := 0;
  507.   FHead^.btChild[aaLeft] := nil;
  508. end;
  509. {--------}
  510. procedure TaaBinaryTree.Delete(aNode : PaaBTNode);
  511. var
  512.   HaveLeftChild : boolean;
  513.   AmLeftChild   : boolean;
  514. begin
  515.   if (aNode = nil)then
  516.     raise Exception.Create('TaaBinaryTree.Delete: node is nil');
  517.   {find out whether we have a single child and which one it is; if we
  518.    find that there are two children raise an exception}
  519.   if (aNode.btChild[aaLeft] <> nil) then begin
  520.     if (aNode.btChild[aaRight] <> nil) then
  521.       raise Exception.Create(
  522.           'TaaBinaryTree.Delete: cannot delete this node');
  523.     HaveLeftChild := true;
  524.   end
  525.   else
  526.     HaveLeftChild := false;
  527.   {find out whether we're a left or right child of our parent}
  528.   AmLeftChild := aNode^.btParent^.btChild[aaLeft] = aNode;
  529.   {set the child link of our parent to our child link}
  530.   aNode^.btParent^.btChild[AmLeftChild] :=
  531.      aNode^.btChild[HaveLeftChild];
  532.   if (aNode^.btChild[HaveLeftChild] <> nil) then
  533.     aNode^.btChild[HaveLeftChild]^.btParent := aNode^.btParent;
  534.   {free the node}
  535.   if Assigned(FDispose) then
  536.     FDispose(aNode^.btData);
  537.   nmFreeNode(aNode);
  538.   dec(FCount);
  539. end;
  540. {--------}
  541. function TaaBinaryTree.InsertAt(aParentNode  : PaaBTNode;
  542.                                 aAsLeftChild : boolean;
  543.                                 aItem        : pointer) : PaaBTNode;
  544. begin
  545.   {if the parent node is nil, assume this is inserting the root}
  546.   if (aParentNode = nil) then begin
  547.     aParentNode := FHead;
  548.     aAsLeftChild := true;
  549.   end;
  550.   {check to see the child link isn't already set}
  551.   if (aParentNode^.btChild[aAsLeftChild] <> nil) then
  552.     raise Exception.Create('TaaBinaryTree.InsertAt: cannot insert here');
  553.   {allocate a new node and insert as the required child of the parent}
  554.   Result := nmAllocNode;
  555.   Result^.btParent := aParentNode;
  556.   Result^.btChild[aaLeft] := nil;
  557.   Result^.btChild[aaRight] := nil;
  558.   Result^.btData := aItem;
  559.   Result^.btExtra := 0;
  560.   aParentNode^.btChild[aAsLeftChild] := Result;
  561.   inc(FCount);
  562. end;
  563. {--------}
  564. function TaaBinaryTree.Root : PaaBTNode;
  565. begin
  566.   Result := FHead^.btChild[aaLeft];
  567. end;
  568. {--------}
  569. function TaaBinaryTree.Traverse(aMode         : TaaTraversalMode;
  570.                                 aAction       : TaaProcessNode;
  571.                                 aExtraData    : pointer;
  572.                                 aUseRecursion : boolean) : PaaBTNode;
  573. begin
  574.   Result := nil;
  575.   if (FHead^.btChild[aaLeft] <> nil) then begin
  576.     case aMode of
  577.       tmPreOrder :
  578.         if aUseRecursion then 
  579.           Result := btRecPreOrder(FHead^.btChild[aaLeft], aAction, aExtraData)
  580.         else
  581.           Result := btNoRecPreOrder(aAction, aExtraData);
  582.       tmInOrder :
  583.         if aUseRecursion then
  584.           Result := btRecInOrder(FHead^.btChild[aaLeft], aAction, aExtraData)
  585.         else
  586.           Result := btNoRecInOrder(aAction, aExtraData);
  587.       tmPostOrder :
  588.         if aUseRecursion then
  589.           Result := btRecPostOrder(FHead^.btChild[aaLeft], aAction, aExtraData)
  590.         else
  591.           Result := btNoRecPostOrder(aAction, aExtraData);
  592.       tmLevelOrder :
  593.         Result := btLevelOrder(aAction, aExtraData);
  594.     end;
  595.   end;
  596. end;
  597. {====================================================================}
  598.  
  599.  
  600. {===TaaBinarySearchTree==============================================}
  601. constructor TaaBinarySearchTree.Create(aCompare : TaaCompareFunction;
  602.                                        aDispose : TaaDisposeItem);
  603. begin
  604.   inherited Create;
  605.   FCompare := aCompare;
  606.   FBinTree := TaaBinaryTree.Create(aDispose);
  607. end;
  608. {--------}
  609. destructor TaaBinarySearchTree.Destroy;
  610. begin
  611.   FBinTree.Free;
  612.   inherited Destroy;
  613. end;
  614. {--------}
  615. function TaaBinarySearchTree.bstFindItem(aItem    : pointer;
  616.                                      var aNode    : PaaBTNode;
  617.                                      var aUseLeft : boolean) : boolean;
  618. var
  619.   Walker : PaaBTNode;
  620.   CmpResult : integer;
  621. begin
  622.   Result := false;
  623.   if (FCount = 0) then begin
  624.     aNode := nil;
  625.     aUseLeft := true;
  626.     Exit;
  627.   end;
  628.   Walker := FBinTree.Root;
  629.   CmpResult := FCompare(aItem, Walker^.btData);
  630.   while (CmpResult <> 0) do begin
  631.     if (CmpResult < 0) then begin
  632.       if (Walker^.btChild[aaLeft] = nil) then begin
  633.         aNode := Walker;
  634.         aUseLeft := true;
  635.         Exit;
  636.       end;
  637.       Walker := Walker^.btChild[aaLeft];
  638.     end
  639.     else begin
  640.       if (Walker^.btChild[aaRight] = nil) then begin
  641.         aNode := Walker;
  642.         aUseLeft := false;
  643.         Exit;
  644.       end;
  645.       Walker := Walker^.btChild[aaRight];
  646.     end;
  647.     CmpResult := FCompare(aItem, Walker^.btData);
  648.   end;
  649.   Result := true;
  650.   aNode := Walker;
  651. end;
  652. {--------}
  653. function TaaBinarySearchTree.bstFindNodeToDelete(aItem : pointer) : PaaBTNode;
  654. var
  655.   Walker  : PaaBTNode;
  656.   Node    : PaaBTNode;
  657.   UseLeft : boolean;
  658.   Temp    : pointer;
  659. begin
  660.   {attempt to find the item; signal error if not found}
  661.   if not bstFindItem(aItem, Node, UseLeft) then
  662.     raise Exception.Create('TaaBinarySearchTree.Delete: item not found');
  663.   {if the node has two children, find the largest node that is smaller
  664.    than the one we want to delete, and swap over the items}
  665.   if (Node^.btChild[aaLeft] <> nil) and
  666.      (Node^.btChild[aaRight] <> nil) then begin
  667.     Walker := Node^.btChild[aaLeft];
  668.     while (Walker^.btChild[aaRight] <> nil) do
  669.       Walker := Walker^.btChild[aaRight];
  670.     Temp := Walker^.btData;
  671.     Walker^.btData := Node^.btData;
  672.     Node^.btData := Temp;
  673.     Node := Walker;
  674.   end;
  675.   {return the node to delete}
  676.   Result := Node;
  677. end;
  678. {--------}
  679. function TaaBinarySearchTree.bstInsertPrim(aItem    : pointer;
  680.                                        var aExists  : boolean;
  681.                                        var aUseLeft : boolean) : PaaBTNode;
  682. begin
  683.   {first, attempt to find the item; if found, return it}
  684.   if bstFindItem(aItem, Result, aUseLeft) then
  685.     aExists := true
  686.   {otherwise, this returns a node, so insert there}
  687.   else begin
  688.     aExists := false;
  689.     Result := FBinTree.InsertAt(Result, aUseLeft, aItem);
  690.     inc(FCount);
  691.   end;
  692. end;
  693. {--------}
  694. procedure TaaBinarySearchTree.Clear;
  695. begin
  696.   FBinTree.Clear;
  697.   FCount := 0;
  698. end;
  699. {--------}
  700. procedure TaaBinarySearchTree.Delete(aItem : pointer);
  701. begin
  702.   {delete the node}
  703.   FBinTree.Delete(bstFindNodeToDelete(aItem));
  704.   dec(FCount);
  705. end;
  706. {--------}
  707. function TaaBinarySearchTree.Find(aKeyItem : pointer) : pointer;
  708. var
  709.   Node : PaaBTNode;
  710.   UseLeft : boolean;
  711. begin
  712.   if bstFindItem(aKeyItem, Node, UseLeft) then
  713.     Result := Node^.btData
  714.   else
  715.     Result := nil;
  716. end;
  717. {--------}
  718. procedure TaaBinarySearchTree.Insert(aItem : pointer);
  719. var
  720.   UseLeft  : boolean;
  721.   WasFound : boolean;
  722. begin
  723.   bstInsertPrim(aItem, WasFound, UseLeft);
  724.   if WasFound then
  725.     raise Exception.Create(
  726.        'TaaBinarySearchTree.Insert: duplicate keys not allowed');
  727. end;
  728. {--------}
  729. function TaaBinarySearchTree.InsertOrGet(aItem    : pointer;
  730.                                      var aCurItem : pointer)
  731.                                                   : boolean;
  732. var
  733.   UseLeft  : boolean;
  734.   WasFound : boolean;
  735.   Node     : PaaBTNode;
  736. begin
  737.   Node := bstInsertPrim(aItem, WasFound, UseLeft);
  738.   Result := not WasFound;
  739.   aCurItem := Node^.btData;
  740. end;
  741. {--------}
  742. function TaaBinarySearchTree.Traverse(aMode         : TaaTraversalMode;
  743.                                       aAction       : TaaProcessNode;
  744.                                       aExtraData    : pointer;
  745.                                       aUseRecursion : boolean) : pointer;
  746. var
  747.   Node : PaaBTNode;
  748. begin
  749.   Node := FBinTree.Traverse(aMode, aAction, aExtraData, aUseRecursion);
  750.   if (Node = nil) then
  751.     Result := nil
  752.   else
  753.     Result := Node^.btData;
  754. end;
  755. {====================================================================}
  756.  
  757.  
  758. function IsRed(aNode : PaaBTNode) : boolean;
  759. begin
  760.   if (aNode = nil) then
  761.     Result := false
  762.   else
  763.     Result := aNode^.btColor = aaRed;
  764. end;
  765.  
  766.  
  767. {===TaaRedBlackTree==================================================}
  768. procedure TaaRedBlackTree.Delete(aItem : pointer);
  769. var
  770.   Node       : PaaBTNode;
  771.   Dad        : PaaBTNode;
  772.   Child      : PaaBTNode;
  773.   Brother    : PaaBTNode;
  774.   FarNephew  : PaaBTNode;
  775.   NearNephew : PaaBTNode;
  776.   IsBalanced : boolean;
  777.   IsLeftChild: boolean;
  778. begin
  779.   {fool the compiler's warning generator}
  780.   Brother := nil;
  781.   Dad := nil;
  782.   IsLeftChild := false;
  783.   {find the node to delete; this node will have but one child}
  784.   Node := bstFindNodeToDelete(aItem);
  785.   {if the node is red, or is the root, delete it with impunity}
  786.   if (Node^.btColor = aaRed) or
  787.      (Node = FBinTree.Root) then begin
  788.     FBinTree.Delete(Node);
  789.     dec(FCount);
  790.     Exit;
  791.   end;
  792.   {if the node's only child is red, recolor the child black, and
  793.    delete the node}
  794.   if (Node^.btChild[aaLeft] = nil) then
  795.     Child := Node^.btChild[aaRight]
  796.   else
  797.     Child := Node^.btChild[aaLeft];
  798.   if IsRed(Child) then begin
  799.     Child^.btColor := aaBlack;
  800.     FBinTree.Delete(Node);
  801.     dec(FCount);
  802.     Exit;
  803.   end;
  804.   {at this point, the node we have to delete is Node, and we
  805.    know that Child is black (and also maybe nil!), the parent (ie,
  806.    Node) is black, and there is a grandparent (which will soon be the
  807.    parent); the parent's brother also exists because of the black node
  808.    rule}
  809.  
  810.   {if the Child is nil, we'll have to help the loop a little bit and
  811.    set the parent and brother and whether this child is a left child
  812.    or not}
  813.   if (Child = nil) then begin
  814.     Dad := Node^.btParent;
  815.     if (Node = Dad^.btChild[aaLeft]) then begin
  816.       IsLeftChild := true;
  817.       Brother := Dad^.btChild[aaRight];
  818.     end
  819.     else begin
  820.       IsLeftChild := false;
  821.       Brother := Dad^.btChild[aaLeft];
  822.     end;
  823.   end;
  824.   {delete the node we want to, we have no more need of it}
  825.   FBinTree.Delete(Node);
  826.   dec(FCount);
  827.   Node := Child;
  828.   {in a loop, continue applying the red-black deletion balancing
  829.    algorithms until the tree is balanced}
  830.   repeat
  831.     {assume we'll balance it this time}
  832.     IsBalanced := true;
  833.     {we are balanced if the node is the root, so assume it isn't}
  834.     if (Node <> FBinTree.Root) then begin
  835.       {get the parent and the brother}
  836.       if (Node <> nil) then begin
  837.         Dad := Node^.btParent;
  838.         if (Node = Dad^.btChild[aaLeft]) then begin
  839.           IsLeftChild := true;
  840.           Brother := Dad^.btChild[aaRight];
  841.         end
  842.         else begin
  843.           IsLeftChild := false;
  844.           Brother := Dad^.btChild[aaLeft];
  845.         end;
  846.       end;
  847.       {we need a black brother, so if the brother is currently red,
  848.        color the parent red, the brother black, and promote the brother;
  849.        then go round loop again}
  850.       if (Brother^.btColor = aaRed) then begin
  851.         Dad^.btColor := aaRed;
  852.         Brother^.btColor := aaBlack;
  853.         rbtPromote(Brother);
  854.         IsBalanced := false;
  855.       end
  856.       {otherwise the brother is black}
  857.       else begin
  858.         {get the nephews}
  859.         if IsLeftChild then begin
  860.           FarNephew := Brother^.btChild[aaRight];
  861.           NearNephew := Brother^.btChild[aaLeft];
  862.         end
  863.         else begin
  864.           FarNephew := Brother^.btChild[aaLeft];
  865.           NearNephew := Brother^.btChild[aaRight];
  866.         end;
  867.         {if the far nephew is red (note that it could be nil!), color
  868.          it black, color the brother the same as the parent, color the
  869.          parent black, and then promote the brother; we're then done}
  870.         if IsRed(FarNephew) then begin
  871.           FarNephew^.btColor := aaBlack;
  872.           Brother^.btColor := Dad^.btColor;
  873.           Dad^.btColor := aaBlack;
  874.           rbtPromote(Brother);
  875.         end
  876.         {otherwise the far nephew is black}
  877.         else begin
  878.           {if the near nephew is red (note that it could be nil!), color
  879.            it the same color as the parent, color the parent black, and
  880.            zig-zag promote the nephew; we're then done}
  881.           if IsRed(NearNephew) then begin
  882.             NearNephew^.btColor := Dad^.btColor;
  883.             Dad^.btColor := aaBlack;
  884.             rbtPromote(rbtPromote(NearNephew));
  885.           end
  886.           {otherwise the near nephew is also black}
  887.           else begin
  888.             {if the parent is red, color it black and the brother red,
  889.              and we're done}
  890.             if (Dad^.btColor = aaRed) then begin
  891.               Dad^.btColor := aaBlack;
  892.               Brother^.btColor := aaRed;
  893.             end
  894.             {otherwise the parent is black: color the brother red and
  895.              start over with the parent}
  896.             else begin
  897.               Brother^.btColor := aaRed;
  898.               Node := Dad;
  899.               IsBalanced := false;
  900.             end;
  901.           end;
  902.         end;
  903.       end;
  904.     end;
  905.   until IsBalanced;
  906. end;
  907. {--------}
  908. procedure TaaRedBlackTree.Insert(aItem : pointer);
  909. var
  910.   Node     : PaaBTNode;
  911.   WasFound : boolean;
  912.   UseLeft  : boolean;
  913. begin
  914.   {insert the new item, get back the node that was inserted and its
  915.    relationship to its parent}
  916.   Node := bstInsertPrim(aItem, WasFound, UseLeft);
  917.   if WasFound then
  918.     raise Exception.Create(
  919.        'TaaRedBlackTree.Insert: duplicate keys not allowed');
  920.   {balance the tree}
  921.   rbtBalanceAfterInsert(Node);
  922. end;
  923. {--------}
  924. function TaaRedBlackTree.InsertOrGet(aItem    : pointer;
  925.                                  var aCurItem : pointer) : boolean;
  926. var
  927.   Node     : PaaBTNode;
  928.   WasFound : boolean;
  929.   UseLeft  : boolean;
  930. begin
  931.   {insert the new item, get back the node that was inserted and its
  932.    relationship to its parent}
  933.   Node := bstInsertPrim(aItem, WasFound, UseLeft);
  934.   aCurItem := Node^.btData;
  935.   Result := not WasFound;
  936.   {balance the tree, if inserted}
  937.   if Result then
  938.     rbtBalanceAfterInsert(Node);
  939. end;
  940. {--------}
  941. procedure TaaRedBlackTree.rbtBalanceAfterInsert(aNode  : PaaBTNode);
  942. var
  943.   Dad      : PaaBTNode;
  944.   Grandad  : PaaBTNode;
  945.   Uncle    : PaaBTNode;
  946.   IsLeftChild    : boolean;
  947.   DadIsLeftChild : boolean;
  948.   IsBalanced     : boolean;
  949. begin
  950.   {the node passed is the new one; color it red}
  951.   aNode^.btColor := aaRed;
  952.  
  953.   {in a loop, continue applying the red-black insertion balancing
  954.    algorithms until the tree is balanced}
  955.   repeat
  956.     {assume we'll balance it this time}
  957.     IsBalanced := true;
  958.     {if the node is the root, we're done and the tree is balanced, so
  959.      assume we're not at the root}
  960.     if (aNode <> FBinTree.Root) then begin
  961.       {as we're not at the root, get the parent of this node}
  962.       Dad := aNode^.btParent;
  963.       {if the parent is black, we're done and the tree is balanced, so
  964.        assume that the parent is red}
  965.       if (Dad^.btColor = aaRed) then begin
  966.         {if the parent is the root, just color it black and we're
  967.          done}
  968.         if (Dad = FBinTree.Root) then
  969.           Dad^.btColor := aaBlack
  970.         {otherwise the parent has a parent of its own}
  971.         else begin
  972.           {get the grandparent and color it red}
  973.           Grandad := Dad^.btParent;
  974.           Grandad^.btColor := aaRed;
  975.           {get the uncle node}
  976.           if (Grandad^.btChild[aaLeft] = Dad) then begin
  977.             DadIsLeftChild := true;
  978.             Uncle := Grandad^.btChild[aaRight];
  979.           end
  980.           else begin
  981.             DadIsLeftChild := false;
  982.             Uncle := Grandad^.btChild[aaLeft];
  983.           end;
  984.           {if the uncle is also red (note that the uncle can be nil!),
  985.            color the parent black, the uncle black and start over with
  986.            the grandparent}
  987.           if IsRed(Uncle) then begin
  988.             Dad^.btColor := aaBlack;
  989.             Uncle^.btColor := aaBlack;
  990.             aNode := Grandad;
  991.             IsBalanced := false;
  992.           end
  993.           {otherwise the uncle is black}
  994.           else begin
  995.             {if the node we inserted has the same relationship with
  996.              its parent as the parent has with the grandparent, color
  997.              the parent black and promote it; we're then done}
  998.             IsLeftChild := aNode = Dad^.btChild[aaLeft];
  999.             if IsLeftChild = DadIsLeftChild then begin
  1000.               Dad^.btColor := aaBlack;
  1001.               rbtPromote(Dad);
  1002.             end
  1003.             {otherwise color the node black and zig-zag promote it;
  1004.              we're then done}
  1005.             else begin
  1006.               aNode^.btColor := aaBlack;
  1007.               rbtPromote(rbtPromote(aNode));
  1008.             end;
  1009.           end;
  1010.         end;
  1011.       end;
  1012.     end;
  1013.   until IsBalanced;
  1014. end;
  1015. {--------}
  1016. function TaaRedBlackTree.rbtPromote(aNode  : PaaBTNode) : PaaBTNode;
  1017. var
  1018.   Parent : PaaBTNode;
  1019. begin
  1020.   {make a note of the parent of the node we're promoting}
  1021.   Parent := aNode^.btParent;
  1022.  
  1023.   {in both cases there are 6 links to be broken and remade: the node's
  1024.    link to its child and vice versa, the node's link with its parent
  1025.    and vice versa and the parent's link with its parent and vice
  1026.    versa; note that the node's child could be nil}
  1027.  
  1028.   {promote a left child = right rotation of parent}
  1029.   if (Parent^.btChild[aaLeft] = aNode) then begin
  1030.     Parent^.btChild[aaLeft] := aNode^.btChild[aaRight];
  1031.     if (Parent^.btChild[aaLeft] <> nil) then
  1032.       Parent^.btChild[aaLeft]^.btParent := Parent;
  1033.     aNode^.btParent := Parent^.btParent;
  1034.     if (aNode^.btParent^.btChild[aaLeft] = Parent) then
  1035.       aNode^.btParent^.btChild[aaLeft] := aNode
  1036.     else
  1037.       aNode^.btParent^.btChild[aaRight] := aNode;
  1038.     aNode^.btChild[aaRight] := Parent;
  1039.     Parent^.btParent := aNode;
  1040.   end
  1041.   {promote a right child = left rotation of parent}
  1042.   else begin
  1043.     Parent^.btChild[aaRight] := aNode^.btChild[aaLeft];
  1044.     if (Parent^.btChild[aaRight] <> nil) then
  1045.       Parent^.btChild[aaRight]^.btParent := Parent;
  1046.     aNode^.btParent := Parent^.btParent;
  1047.     if (aNode^.btParent^.btChild[aaLeft] = Parent) then
  1048.       aNode^.btParent^.btChild[aaLeft] := aNode
  1049.     else
  1050.       aNode^.btParent^.btChild[aaRight] := aNode;
  1051.     aNode^.btChild[aaLeft] := Parent;
  1052.     Parent^.btParent := aNode;
  1053.   end;
  1054.   {return the node we promoted}
  1055.   Result := aNode;
  1056. end;
  1057. {====================================================================}
  1058.  
  1059.  
  1060. {===Drawing a binary tree============================================}
  1061. type
  1062.   PNodePosn = ^TNodePosn;
  1063.   TNodePosn = packed record
  1064.     npStrip  : integer;
  1065.     npColumn : integer;
  1066.   end;
  1067. {--------}
  1068. procedure DrawBinaryTree(aTree      : TObject;
  1069.                          aDrawNode  : TaaDrawBinaryNode;
  1070.                          aExtraData : pointer);
  1071.   {------}
  1072.   function GenPosNode(aNode   : PaaBTNode;
  1073.                       aStrip  : integer;
  1074.                   var aColumn : integer) : PaaBTNode;
  1075.   var
  1076.     OurPosNode : PaaBTNode;
  1077.     OurPosition : PNodePosn;
  1078.   begin
  1079.     {allocate ourselves a node and a position}
  1080.     OurPosNode := nmAllocNode;
  1081.     FillChar(OurPosNode^, sizeof(OurPosNode^), 0);
  1082.     New(OurPosition);
  1083.     OurPosNode^.btData := OurPosition;
  1084.  
  1085.     {visit the left subtree}
  1086.     if (aNode^.btChild[aaLeft] <> nil) then begin
  1087.       OurPosNode^.btChild[aaLeft] :=
  1088.          GenPosNode(aNode^.btChild[aaLeft], succ(aStrip), aColumn);
  1089.       OurPosNode^.btChild[aaLeft]^.btParent := OurPosNode;
  1090.     end;
  1091.  
  1092.     {store our position, increment the column since we're there now}
  1093.     OurPosition^.npStrip := aStrip;
  1094.     OurPosition^.npColumn := aColumn;
  1095.     inc(aColumn);
  1096.  
  1097.     {visit the right subtree}
  1098.     if (aNode^.btChild[aaRight] <> nil) then begin
  1099.       OurPosNode^.btChild[aaRight] :=
  1100.         GenPosNode(aNode^.btChild[aaRight], succ(aStrip), aColumn);
  1101.       OurPosNode^.btChild[aaRight]^.btParent := OurPosNode;
  1102.     end;
  1103.  
  1104.     Result := OurPosNode;
  1105.   end;
  1106.   {------}
  1107.   procedure DestroyPosNode(aNode : PaaBTNode);
  1108.   begin
  1109.     {destroy the left subtree}
  1110.     if (aNode^.btChild[aaLeft] <> nil) then
  1111.       DestroyPosNode(aNode^.btChild[aaLeft]);
  1112.     {destroy the right subtree}
  1113.     if (aNode^.btChild[aaRight] <> nil) then
  1114.       DestroyPosNode(aNode^.btChild[aaRight]);
  1115.     {destroy this node}
  1116.     Dispose(PNodePosn(aNode^.btData));
  1117.     nmFreeNode(aNode);
  1118.   end;
  1119.   {------}
  1120. var
  1121.   BinTree : TaaBinaryTree;
  1122.   Strip, Column : integer;
  1123.   PStrip, PColumn : integer;
  1124.   PosRoot : PaaBTNode;
  1125.   Queue   : TaaQueue;
  1126.   Node    : PaaBTNode;
  1127.   PosNode : PaaBTNode;
  1128. begin
  1129.   {get a hold of the actual binary tree}
  1130.   if (aTree is TaaBinaryTree) then
  1131.     BinTree := TaaBinaryTree(aTree)
  1132.   else if (aTree is TaaBinarySearchTree) then
  1133.     BinTree := TaaBinarySearchTree(aTree).BinaryTree
  1134.   else
  1135.     Exit;
  1136.  
  1137.   {simple case first}
  1138.   if (BinTree.Count = 0) then
  1139.     Exit;
  1140.  
  1141.   {--first pass--}
  1142.   Strip := 0;
  1143.   Column := 0;
  1144.   PosRoot := GenPosNode(BinTree.Root, Strip, Column);
  1145.  
  1146.   {--second pass--}
  1147.   try
  1148.     {create the queue}
  1149.     Queue := TaaQueue.Create;
  1150.     try
  1151.       {enqueue the roots}
  1152.       Queue.Enqueue(BinTree.Root);
  1153.       Queue.Enqueue(PosRoot);
  1154.       {continue until the queue is empty}
  1155.       while not Queue.IsEmpty do begin
  1156.         {get the nodes at the head of the queue}
  1157.         Node := Queue.Dequeue;
  1158.         PosNode := Queue.Dequeue;
  1159.         {draw the node}
  1160.         if (PosNode = PosRoot) then begin
  1161.           PStrip := -1;
  1162.           PColumn := -1;
  1163.         end
  1164.         else with PNodePosn(PosNode^.btParent^.btData)^ do begin
  1165.           PStrip := npStrip;
  1166.           PColumn := npColumn;
  1167.         end;
  1168.         with PNodePosn(PosNode^.btData)^ do
  1169.           aDrawNode(Node, npStrip, npColumn,
  1170.                           PStrip, PColumn, aExtraData);
  1171.         {enqueue the left children, if the first is not nil}
  1172.         if (Node^.btChild[aaLeft] <> nil) then begin
  1173.           Queue.Enqueue(Node^.btChild[aaLeft]);
  1174.           Queue.Enqueue(PosNode^.btChild[aaLeft]);
  1175.         end;
  1176.         {enqueue the right children, if the first is not nil}
  1177.         if (Node^.btChild[aaRight] <> nil) then begin
  1178.           Queue.Enqueue(Node^.btChild[aaRight]);
  1179.           Queue.Enqueue(PosNode^.btChild[aaRight]);
  1180.         end;
  1181.       end;
  1182.     finally
  1183.       {destroy the queue}
  1184.       Queue.Free;
  1185.     end;
  1186.   finally
  1187.     {now destroy the position binary tree}
  1188.     DestroyPosNode(PosRoot);
  1189.   end;
  1190. end;
  1191. {====================================================================}
  1192.  
  1193.  
  1194. procedure FinalizeUnit; far;
  1195. var
  1196.   Temp : PnmPage;
  1197. begin
  1198.   {destroy all the single node pages}
  1199.   Temp := nmPageList;
  1200.   while (Temp <> nil) do begin
  1201.     nmPageList := Temp^.nmpNext;
  1202.     Dispose(Temp);
  1203.     Temp := nmPageList;
  1204.   end;
  1205. end;
  1206.  
  1207. initialization
  1208.   nmFreeList := nil;
  1209.   nmPageList := nil;
  1210.   {$IFDEF Windows}
  1211.   AddExitProc(FinalizeUnit);
  1212.   {$ENDIF}
  1213.  
  1214. {$IFDEF Win32}
  1215. finalization
  1216.   FinalizeUnit;
  1217. {$ENDIF}
  1218.  
  1219. end.
  1220.  
  1221.